package main

import (
	"encoding/binary"
	"errors"
	"fmt"
	"iot-base/common/logger"
	"iot-base/common/modbus"
	"strconv"

	"iot-base/common/cache"
	"iot-base/common/notify"
	"iot-base/devc/common/loader"
	"sync"
	"time"
)

var (
	connection map[string]modbus.Client
	mux        sync.Mutex
)

func init() {
	connection = make(map[string]modbus.Client)
}

func main() {
	loader.SetParam(false, "aidi", 1, GetTask)
	loader.SubCtrlHandler(Control)
	wg := sync.WaitGroup{}
	wg.Add(1)
	wg.Wait()
}

func GetTask(id string, thing *cache.ThingInfo, v interface{}, round int64) (interface{}, error) {
	logger.Log.Info("in aidi------------------------" + id)
	ty, ok := thing.Params["type"]
	if !ok {
		logger.Log.Error("type err")
		return nil, errors.New("type err")
	}
	ip, ok := thing.Params["IP"]
	if !ok {
		fmt.Println("IP err")
		return nil, errors.New("ip err")
	}
	port, ok := thing.Params["Port"]
	if !ok {
		fmt.Println("port err")
		return nil, errors.New("port err")
	}
	slaveID, ok := thing.Params["slaveID"]
	if !ok {
		fmt.Println("slaveID err")
		return nil, errors.New("slaveID err")
	}
	client := new(modbus.Client)
	switch ty {
	case "dtu":
		confip := ip + ":" + port
		if cli, ok := connection[confip]; !ok {
			slaveid, err := strconv.ParseUint(slaveID, 10, 0)
			handler := modbus.NewRTUTCPClientHandler(confip)
			handler.SlaveId = uint8(slaveid)
			handler.Timeout = 500 * time.Millisecond
			err = handler.Connect()
			defer handler.Close()
			if err != nil {
				logger.Log.Error("dtu connect err!")
				fmt.Println("dtu connect err!")
				return nil, errors.New("dtu connect err")
			}
			*client = modbus.NewClient(handler)
			connection[confip] = *client
		} else {
			*client = cli
		}
		fmt.Println("serial start:------------------------------", *client)
		mux.Lock()
		msg, err := SendMsg(id, *client, thing)
		mux.Unlock()
		if err != nil {
			logger.Log.Error(err.Error())
		}
		return msg, err
	case "tcp":
		slaveid, err := strconv.ParseUint(slaveID, 10, 0)
		handler := modbus.NewRTUTCPClientHandler(fmt.Sprintf("%s:%s", ip, port))
		handler.SlaveId = uint8(slaveid)
		handler.Timeout = 500 * time.Millisecond
		err = handler.Connect()
		if err != nil {
			logger.Log.Error("tcp connect err!")
			fmt.Println("tcp connect err!")
			return nil, errors.New("tcp connect err")
		}
		defer handler.Close()
		*client = modbus.NewClient(handler)
		fmt.Println("tcp start:------------------------------", *client)
	default:
		logger.Log.Error("no this type")
		return nil, errors.New("no this type")
	}
	return SendMsg(id, *client, thing)
}

func ReadDI(client modbus.Client, count int) (*string, error) {
	res, err := client.ReadDiscreteInputs(0, 8)
	if err != nil {
		logger.Log.Error("read di err!" + err.Error())
		return nil, err
	}
	result := fmt.Sprintf("%d", (res[0]>>count)&0x1)
	return &result, nil
}

func ReadAI(client modbus.Client, thing *cache.ThingInfo, count int) (*float32, error) {
	add := thing.GetThingParam("add", "")
	addint, _ := strconv.ParseFloat(add, 32)
	mul := thing.Params["mul"]
	mulint, _ := strconv.ParseFloat(mul, 32)
	res, err := client.ReadHoldingRegisters(50, 8)
	if err != nil {
		fmt.Println("read err:", err)
		logger.Log.Error("read err:" + err.Error())
		return nil, err
	}
	fmt.Println("res:", res, err)
	if len(res) < (count+1)*2 {
		logger.Log.Error("return data len is err:" + fmt.Sprintf("%d", len(res)))
		return nil, errors.New("return data len is err:" + fmt.Sprintf("%d", len(res)))
	}
	bits := binary.BigEndian.Uint16(append(res[(count * 2) : (count+1)*2]))
	tmp := float32(bits)
	fmt.Println("mul,add:", float32(mulint), float32(addint))
	result := float32(0)
	if mulint == 0 {
		result = tmp + float32(addint)
	} else {
		result = (tmp + float32(addint)) * float32(mulint)
	}
	fmt.Println("ai:", result, count)
	if result < 0 {
		result = 0
	}
	if count == 1 {
		fmt.Println("result:", result)
	}
	return &result, nil
}

func SendMsg(id string, client modbus.Client, thing *cache.ThingInfo) (interface{}, error) {
	iid, ok := thing.Params["id"]
	if !ok {
		logger.Log.Error("aidi param id is err!")
		fmt.Println("aidi param id is err!")
	}
	input, ok := thing.Params["input"]
	if ok {
		if input != "" {
			iid = input
		}
	}
	now := time.Now().Unix()
	switch iid {
	case "DI0":
		value, err := ReadDI(client, 0)
		if err != nil {
			logger.Log.Error("DI0 err:" + err.Error())
			return nil, errors.New("DI0 err:" + err.Error())
		}
		notify.RawData(id, "status", "", 0, value, now, now)
	case "DI1":
		value, err := ReadDI(client, 1)
		if err != nil {
			logger.Log.Error("DI1 err:" + err.Error())
			return nil, errors.New("DI1 err:" + err.Error())
		}
		notify.RawData(id, "status", "", 0, value, now, now)
	case "DI2":
		value, err := ReadDI(client, 2)
		if err != nil {
			logger.Log.Error("DI2 err:" + err.Error())
			return nil, errors.New("DI2 err:" + err.Error())
		}
		notify.RawData(id, "status", "", 0, value, now, now)
	case "DI3":
		value, err := ReadDI(client, 3)
		if err != nil {
			logger.Log.Error("DI3 err:" + err.Error())
			return nil, errors.New("DI3 err:" + err.Error())
		}
		notify.RawData(id, "status", "", 0, value, now, now)
	case "DI4":
		value, err := ReadDI(client, 4)
		if err != nil {
			logger.Log.Error("DI4 err:" + err.Error())
			return nil, errors.New("DI4 err:" + err.Error())
		}
		notify.RawData(id, "status", "", 0, value, now, now)
	case "DI5":
		value, err := ReadDI(client, 5)
		if err != nil {
			logger.Log.Error("DI5 err:" + err.Error())
			return nil, errors.New("DI5 err:" + err.Error())
		}
		notify.RawData(id, "status", "", 0, value, now, now)
	case "DI6":
		value, err := ReadDI(client, 6)
		if err != nil {
			logger.Log.Error("DI6 err:" + err.Error())
			return nil, errors.New("DI6 err:" + err.Error())
		}
		notify.RawData(id, "status", "", 0, value, now, now)
	case "DI7":
		value, err := ReadDI(client, 7)
		if err != nil {
			logger.Log.Error("DI7 err:" + err.Error())
			return nil, errors.New("DI7 err:" + err.Error())
		}
		notify.RawData(id, "status", "", 0, value, now, now)
	case "AI0":
		value, err := ReadAI(client, thing, 0)
		if err != nil {
			logger.Log.Error("AI0 err:" + err.Error())
			return nil, errors.New("AI0 err:" + err.Error())
		}
		notify.RawData(id, "status", "", 0, value, now, now)
	case "AI1":
		value, err := ReadAI(client, thing, 1)
		if err != nil {
			logger.Log.Error("AI1 err:" + err.Error())
			return nil, errors.New("AI1 err:" + err.Error())
		}
		notify.RawData(id, "status", "", 0, value, now, now)
	case "AI2":
		value, err := ReadAI(client, thing, 2)
		if err != nil {
			logger.Log.Error("AI2 err:" + err.Error())
			return nil, errors.New("AI2 err:" + err.Error())
		}
		notify.RawData(id, "status", "", 0, value, now, now)
	case "AI3":
		value, err := ReadAI(client, thing, 3)
		if err != nil {
			logger.Log.Error("AI3 err:" + err.Error())
			return nil, errors.New("AI3 err:" + err.Error())
		}
		notify.RawData(id, "status", "", 0, value, now, now)
	case "AI4":
		value, err := ReadAI(client, thing, 4)
		if err != nil {
			logger.Log.Error("AI4 err:" + err.Error())
			return nil, errors.New("AI4 err:" + err.Error())
		}
		notify.RawData(id, "status", "", 0, value, now, now)
	case "AI5":
		value, err := ReadAI(client, thing, 5)
		if err != nil {
			logger.Log.Error("AI5 err:" + err.Error())
			return nil, errors.New("AI5 err:" + err.Error())
		}
		notify.RawData(id, "status", "", 0, value, now, now)
	case "AI6":
		value, err := ReadAI(client, thing, 6)
		if err != nil {
			logger.Log.Error("AI6 err:" + err.Error())
			return nil, errors.New("AI6 err:" + err.Error())
		}
		notify.RawData(id, "status", "", 0, value, now, now)
	case "AI7":
		value, err := ReadAI(client, thing, 7)
		if err != nil {
			logger.Log.Error("AI7 err:" + err.Error())
			return nil, errors.New("AI7 err:" + err.Error())
		}
		notify.RawData(id, "status", "", 0, value, now, now)
	default:
		fmt.Println("no this id param!")
		logger.Log.Error("no this id param")
		return nil, errors.New("no this id param")
	}
	return nil, nil
}
